#include "robinsonmatrixihm.h"

#include "Algo.h"
#include "Util.h"
#include "TEST.h"

#include <QTableWidgetItem>
#include <QDoubleSpinBox>
#include <QFileDialog>
#include <map>
#include <time.h>
#include <math.h>
#include <stdlib.h>
#include <iostream>
#include <sstream>

using namespace std;

namespace RobinsonMatrixIHM
{	
	RobinsonMatrixIHM::RobinsonMatrixIHM(QWidget *parent)
	    : QWidget(parent)
	{
		srand(time(0));
		ui.setupUi(this);
		
		connect(ui.exec, SIGNAL(clicked()),
			        this, SLOT(exec()));
		connect(ui.clean, SIGNAL(clicked()),
					this, SLOT(clean()));
		connect(ui.resize, SIGNAL(clicked()),
					this, SLOT(resize()));
		connect(ui.manuel, SIGNAL(clicked()),
					this, SLOT(fillManualy()));
		connect(ui.rand_gen, SIGNAL(clicked()),
					this, SLOT(randomGen()));
		connect(ui.rand, SIGNAL(clicked()),
					this, SLOT(randomMatrix()));
		connect(ui.loadDissMatrix, SIGNAL(clicked()),
					this, SLOT(loadMatrix()));
		
		ui.menu_Rand->hide();
		ui.menu_matrixParam->hide();
	}
	
	RobinsonMatrixIHM::~RobinsonMatrixIHM()
	{
	
	}

	void RobinsonMatrixIHM::exec()
	{
		if ( _dissimilarityMatrix.getSize() > 0 )
			_totalOrder = Algo::fittingByRobinson(_dissimilarityMatrix, _robinsonMatrix, _delta, ui.fast->isChecked());
		ostringstream out;
		out << "Total Order = ";
		for ( unsigned int i = 0; i < _totalOrder.size(); ++i )
			out << _totalOrder[i] << " ";
		ui.info->append(out.str().c_str());
		ui.robinsonMatrix->setRowCount(_robinsonMatrix.getSize());
		ui.robinsonMatrix->setColumnCount(_robinsonMatrix.getSize());
		showMatrix(_robinsonMatrix, permuteMatrix(_colors, _totalOrder),ui.robinsonMatrix);
	}
	
	void RobinsonMatrixIHM::loadMatrix()
	{
		ui.menu_Rand->hide();
		ui.menu_matrixParam->hide();
		QString s = fileOpen();
		if ( s.isEmpty() )
			return;
		
    	ifstream file( s.toStdString().c_str() );
        if( !file )
        	ui.info->append("Can't open file!");
        else
        {
        	clean();
        	file >> _dissimilarityMatrix;
        	initColorsMatrix();
        	showMatrix( _dissimilarityMatrix, _colors, ui.dissimilarityMatrix );
        }
	}
	
	QString RobinsonMatrixIHM::fileOpen()
	 {
	    QString fn = QFileDialog::getOpenFileName(this, tr("Open File..."),
	                 	QString(), tr("All Files (*)"));
        return fn;
	 }
	
	void RobinsonMatrixIHM::resize()
	{
		clean();
		ui.dissimilarityMatrix->setBaseSize(ui.matrixSize->value()*10, ui.dissimilarityMatrix->rowHeight(0));
		ui.dissimilarityMatrix->setRowCount(ui.matrixSize->value());
		ui.dissimilarityMatrix->setColumnCount(ui.matrixSize->value());
		for ( unsigned int i = 0; i < ui.matrixSize->value(); ++i )
		{
			ui.dissimilarityMatrix->setColumnWidth(i,10);
			ui.dissimilarityMatrix->setItem(i,i,new QTableWidgetItem("0"));
		}

		connect(ui.dissimilarityMatrix, SIGNAL(cellChanged(int,int)),
							this, SLOT(setValue(int,int)));
	}
	
	void RobinsonMatrixIHM::fillManualy()
	{
		ui.menu_Rand->hide();
		ui.menu_matrixParam->show();
		ui.resize->show();
	}
	
	void RobinsonMatrixIHM::setValue(int i, int j)
	{
		if ( ui.dissimilarityMatrix->item(i,j)->text().isEmpty() )
			return;
		
		disconnect(ui.dissimilarityMatrix, SIGNAL(cellChanged(int,int)),
				this, SLOT(setValue(int,int)));
		int val;
		istringstream iss(ui.dissimilarityMatrix->item(i,j)->text().toStdString());
		iss>>val;
		ui.dissimilarityMatrix->setItem(j,i,new QTableWidgetItem(ui.dissimilarityMatrix->item(i,j)->text()));

		int tmp;
		tmp = 4*(log(val)+5);
		if ( tmp > ui.dissimilarityMatrix->columnWidth(i) )
			ui.dissimilarityMatrix->setColumnWidth(i,tmp);
		
		tmp = 4*(log(val)+5);
		if ( tmp > ui.dissimilarityMatrix->columnWidth(j) )
			ui.dissimilarityMatrix->setColumnWidth(j,tmp);

		connect(ui.dissimilarityMatrix, SIGNAL(cellChanged(int,int)),
							this, SLOT(setValue(int,int)));
	}
	
	void RobinsonMatrixIHM::randomMatrix()
	{
		clean();
		ui.menu_Rand->show();
		ui.menu_matrixParam->show();
		ui.resize->hide();
	}
	
	void RobinsonMatrixIHM::clean()
	{
		ui.matrixSize->clear();
		ui.info->clear();
		
		for ( int i = 0; i < _dissimilarityMatrix.getSize(); ++i )
			for ( int j = 0; j < _dissimilarityMatrix.getSize(); ++j )
				delete ui.dissimilarityMatrix->item(i,j);

		for ( int i = 0; i < _robinsonMatrix.getSize(); ++i )
			for ( int j = 0; j < _robinsonMatrix.getSize(); ++j )
				delete ui.robinsonMatrix->item(i,j);	
				
		ui.robinsonMatrix->clear();
		ui.dissimilarityMatrix->clear();
		_dissimilarityMatrix.clean();
		_robinsonMatrix.clean();
		_totalOrder.clear();
		_colors.clear();
		ui.menu_matrixParam->hide();
	}
	
	void RobinsonMatrixIHM::randomGen()
	{
		
		double a = ui.epsilonVal->value();
		_dissimilarityMatrix.randomGen3(ui.matrixSize->value(), a);
		
		
		_dissimilarityMatrix = generateTestMatrix(_dissimilarityMatrix, 0);
		
		initColorsMatrix();
		showMatrix( _dissimilarityMatrix, _colors, ui.dissimilarityMatrix );
	}
	
	void RobinsonMatrixIHM::showMatrix(const Matrix &m, std::vector<std::vector<QColor* > > colors, QTableWidget *t)
	{
		t->setRowCount(m.getSize());
		t->setColumnCount(m.getSize());
		
		for ( unsigned int i = 0; i < m.getSize(); ++i )
		{	
			int lValMax = 0;
			for ( unsigned int j = 0; j < m.getSize(); ++j )
			{
				ostringstream out;
				if ( lValMax < m.get(i,j) )
					lValMax = m.get(i,j);
				out << m.get(i,j);
				
				QTableWidgetItem *item = new QTableWidgetItem(out.str().c_str());
				item->setBackgroundColor(*colors[i][j]);
				t->setItem(i,j, item);
			}
			t->setColumnWidth(i, 4*(log(lValMax)+5) );
		}
	}
	    
	
	void RobinsonMatrixIHM::initColorsMatrix()
	{
		static map<double, QColor*> valColor;
		
		for ( map<double, QColor*>::iterator it = valColor.begin(); it != valColor.end(); ++it )
			delete it->second;
		valColor.clear();
		
		for ( unsigned int i = 0; i < _dissimilarityMatrix.getSize(); ++i )
			for ( unsigned int j = 0; j < _dissimilarityMatrix.getSize(); ++j )
				if ( valColor.find(_dissimilarityMatrix.get(i,j)) == valColor.end() )
					valColor.insert( pair<double, QColor*>(_dissimilarityMatrix.get(i,j), NULL));
		
		int i = 0;
		for ( map<double, QColor*>::iterator it = valColor.begin(); it != valColor.end(); ++it, ++i )
			valColor[it->first] = new QColor( 255.0-(double)(((double)i*255.0)/valColor.size()),255,255.0-(double)(((double)i*255.0)/(valColor.size()*2)),200);
		
		_colors.resize(_dissimilarityMatrix.getSize());
		for ( unsigned int i = 0; i < _dissimilarityMatrix.getSize(); ++i )
		{	
			_colors[i].resize(_dissimilarityMatrix.getSize());
			for ( unsigned int j = 0; j < _dissimilarityMatrix.getSize(); ++j )
			{
				_colors[i][j] = valColor.find(_dissimilarityMatrix.get(i,j))->second;
			}
		}
	}
	
	vector<vector<QColor* > > RobinsonMatrixIHM::permuteMatrix(vector<vector<QColor* > > colors, std::vector<unsigned int> &order)
	{
		vector<vector<QColor* > > result;
		
		result.resize(colors.size());
		for (unsigned int x = 0; x < order.size(); x++)
		{  
			result[x].resize(colors.size());
			for (unsigned int y = 0; y < order.size(); y++)
                result[x][y] = colors[order[x]][order[y]];
		}
		return result;
	}
}

